#include "sudoku_definition.h"
//------------------------------------------------------------------------------------------------------------
void SudokuDefinition::setIntersection(const set<int>* s1, const set<int>* s2, set<int>* res)
{
	if(s2 == NULL || s2 == NULL || res == NULL)
	{
		cout << "ERROR!! NULL!!\n";
		return;
	}

    BOOST_FOREACH(int i, *s1)
    {
        if(s2->find(i) != s2->end())
        {
            res->insert(i);
        }
    }
}
//------------------------------------------------------------------------------------------------------------
StandardSudoku::StandardSudoku()
{
    size = 9 * 9;
    //generating set of possible values
    for(int i = 0; i <= 9; i++) {
        generalPossibleValues.push_back(i);
    }
    for(int i = 1; i <= size; i++)
        possibleIndices.push_back(i);
    generateGroups();
    buildRelations();
}
//------------------------------------------------------------------------------------------------------------
void SudokuDefinition::getOrderedMapAvailables(map<int,int>* orderedMap,  map<int,set<int>*>* sudBoard)
{
	if(sudBoard == NULL)
	{
		cout << "ERROR!! NULL!!\n";
		return;
	}
    BOOST_FOREACH(int idx, possibleIndices)
    {
        (*sudBoard)[idx]->clear();
    }
}
//------------------------------------------------------------------------------------------------------------
void SudokuDefinition::getGroupsByField(map<int,vector<Group*>*>* groupsByField)
{
	if(groupsByField == NULL)
	{
		cout << "ERROR!! NULL!!\n";
		return;
	}
//	cout << "SudokuDefinition::buildRelations ENTER\n";
	//GroupUnique g;
	BOOST_FOREACH(int i, possibleIndices)
	{
		groupsByField->insert(pair<int,vector<Group*>*>(i,new vector<Group*>));
	}
//    cout << "groups.size()=" << groups.size() << endl;

	BOOST_FOREACH(Group* gr, groups)
	{
		if(gr == NULL)
		{
			cout << "ERROR!! NULL!!\n";
			return;
		}

		if(gr->getIndicesVector() == NULL)
		{
			cout << "ERROR!! NULL!!\n";
			return;
		}
//		cout << "index in group=" << gr->getIndicesVector()->size() << endl;
		BOOST_FOREACH(int i, *(gr->getIndicesVector()))
		{
//		    cout << " i=" << i << endl;
			(*groupsByField)[i]->push_back(gr);
//			if(gv == NULL)
//                cout << "DUPA!!\n";
		}
	}
//	cout << "SudokuDefinition::buildRelations EXIT\n";\

}
//------------------------------------------------------------------------------------------------------------
void SudokuDefinition::buildRelations()
{
    /*
//	cout << "SudokuDefinition::buildRelations ENTER\n";
	//GroupUnique g;
	BOOST_FOREACH(int i, possibleIndices)
	{
		groupsForFieldIdx.insert(pair<int,vector<Group*>*>(i,new vector<Group*>));
	}
//    cout << "groups.size()=" << groups.size() << endl;
	BOOST_FOREACH(Group* gr, groups)
	{
//		cout << "index in group=" << gr->getIndicesVector()->size() << endl;
		BOOST_FOREACH(int i, *(gr->getIndicesVector()))
		{
//		    cout << " i=" << i << endl;
			groupsForFieldIdx[i]->push_back(gr);
//			if(gv == NULL)
//                cout << "DUPA!!\n";
		}
	}
//	cout << "SudokuDefinition::buildRelations EXIT\n";\
    */
}
//------------------------------------------------------------------------------------------------------------
void SudokuDefinition::getAvailableSet(int idx, set<int>* resultSet, map<int,int>* sudBoard)
{
    /*
    int j = 0;
    set<int> tmp, tmp1 = generalPossibleValues;
    vector<Group*>* vog = groupsForFieldIdx[idx];
    BOOST_FOREACH(Group* gr, *vog)
    {
        tmp.clear();
        resultSet->clear();
        gr->getAvailables(idx, sudBoard, &generalPossibleValues, &tmp);
        //availableSet = resultSet;
        SudokuDefinition::setIntersection(&tmp, &tmp1, resultSet);
        /*set_intersection(tmp.begin(), tmp.end(),
                    tmp1.begin(), tmp1.end(),
                    inserter(*(resultSet), resultSet->begin()));
                    */

    /*
        j++;
        cout << "[" << idx << "]" << "[" << j << "] (";
        BOOST_FOREACH(int g, tmp)
        {
            cout << g << " ";
        }
        cout << ") (";
        BOOST_FOREACH(int g, tmp1)
        {
            cout << g << " ";
        }
        cout << ") (";
        BOOST_FOREACH(int g, *resultSet)
        {
            cout << g << " ";
        }
        cout << ")\n";


        tmp1 = *resultSet;
    }
    */
}
//------------------------------------------------------------------------------------------------------------

void StandardSudoku::generateGroups()
{
    int i, ii, j, jj;
    vector<int>* groupVector;// = new vector<int>();
    Group* group;

    //squares
    for(i = 1; i <= 81; i += 27)
    {
        for(j = i; j < i + 9; j += 3)
        {
            //groupVector = new vector<int>();
            group = new GroupUnique(0);
            for(ii = j; ii < j + 27; ii += 9)
            {
                for(jj = ii; jj < ii + 3; jj++)
                {
                    //cout << jj << " ";
                    group->getIndicesVector()->push_back(jj);
                }
            }
            //group = new GroupUnique(groupVector, &possibleIndices, &generalPossibleValues);

            groups.push_back(group);
            //cout << endl;
        }
    }
    //cout << endl;
    //columns
    for(i = 1; i < 10; i++)
    {
        //groupVector = new vector<int>();
        group = new GroupUnique(0);
        for(j = i; j <= 81; j += 9)
        {
            //cout << j << " ";
            group->getIndicesVector()->push_back(j);
        }
        //group = new GroupUnique(groupVector, &possibleIndices, &generalPossibleValues);
        groups.push_back(group);
        //cout << endl;
    }
    //cout << endl;
    //rows
    for(i = 1; i < 81; i += 9)
    {
        //groupVector = new vector<int>();
        group = new GroupUnique(0);
        for(j = i; j < i + 9; j++)
        {
            group->getIndicesVector()->push_back(j);
            //cout << j << " ";
        }
        //group = new GroupUnique(groupVector, &possibleIndices, &generalPossibleValues);
        groups.push_back(group);
        //cout << endl;
    }
    //cout << endl;
}

//------------------------------------------------------------------------------------------------------------
void StandardSudoku::printGroups()
{
    vector<Group*>::iterator groupIt;
    vector<int>::iterator indexIt;

    cout << "StandardSudoku:\n";

    for(groupIt = groups.begin(); groupIt != groups.end(); groupIt++)
    {
        //Group* gr = *groupIt;
        //vector<int>* gid =  gr->getIndicesVector();
        //vector<int> v = *gid;
        indexIt = (*groupIt)->getIndicesVector()->begin();

        for(; indexIt != (*groupIt)->getIndicesVector()->end(); indexIt++)
        {
            cout << *indexIt << " ";
        }
        cout << endl;
    }



}
//------------------------------------------------------------------------------------------------------------
SudokuFromFile::SudokuFromFile(const char* fileName)
{
    if(fileName == NULL)
    {
        cout << "File name is empty."  << endl;
    }
    else if(fetchSudokuRel(fileName) != 0)
    {
        //cout << "ERROR: File " << fileName << " don't found."  << endl;
    }
    else
    {
        //cout << "Done!" << endl;
    }

    //cout << "printing groups: " << endl;
    BOOST_FOREACH(Group* gr, groups)
	{
	    //gr->print();
	}
    buildRelations();
}
//------------------------------------------------------------------------------------------------------------
int SudokuFromFile::fetchSudokuRel(const char* fileName)
{
    cout << "[ENTER]SudokuFromFile::fetchSudokuRel\n";

    int G, n, fi, i, j, tmp;
    char groupType;
    Group* group;
    ifstream read(fileName);
	std::unordered_set<int> possibleIndicesSet;

    //relFile.open(fileName, ios::in);
    //if(!relFile)
      //  return -1;
    //cout << "Starting of fetching of file " << fileName << endl;
    //fetching size
//    read >> size;
    //cout << "size=" << size << endl;
    //fetching indices
    //cout << "indices: ";
/*    for(i = 0; i < size; i++)
    {
        read >> tmp;
        //cout << tmp << " ";
        possibleIndices.push_back(tmp);
    }
*/    //cout << endl;
    //fetching values
    read >> n;
    //cout << "number of values: " << n << "\nvalues: ";
    //read >> emptyValue;
    for(i = 0; i < n; i++)
    {
        read >> tmp;
        //cout << tmp << " ";
        generalPossibleValues.push_back(tmp);
    }

    //cout << endl;
    //fetching groups
    read >> G;
    cout << "G = " << G << endl;
    for(i = 0; i < G; i++)
    {
        //cout << "current group: " << i << ", ";

        read >> n;
        //cout << "amount of elements is " << n << ", " << endl;

        read >> groupType;
        //cout << "groupType: " << groupType << ", ";

        switch(groupType)
        {
            case 'A':
                //cout << "group type is ADD, ";
                //read >> s;
                //cout << "expected sum is " << s << endl;
                //group = new GroupAdd(s, NULL);

                break;
            case 'U':
                //cout << "group type is UNIQUE, ";
                //group = new GroupUnique(NULL);
                group = new GroupUnique(0);
                break;
            default:
                break;
        }
        for(j = 0; j < n; j++)
        {
            read >> fi;
            //cout << "last fi=" << fi << ",";
            //group.add(sudokuBoard.getBoard + fi);
            group->getIndicesVector()->push_back(fi);
            //relations.get(fi).add(group);   //add to relations
            //add to possible indices
            if(possibleIndicesSet.find(fi) == possibleIndicesSet.end())
            {
            	possibleIndicesSet.insert(fi);
            	possibleIndices.push_back(fi);
            	cout << fi << " ";
            }
        }
        groups.push_back(group);
        //cout << endl;
    }
    cout << endl;

    cout << "[EXIT]SudokuFromFile::fetchSudokuRel\n";
    return 0;
}
//------------------------------------------------------------------------------------------------------------
